package com.github.kezhenxu94.playground.java.concurrent.itc;

import java.util.concurrent.Exchanger;

/**
 * <pre>
 * 
 * {@link Exchanger} - 交换器
 * 
 * 一对线程可以在该交换器处停下，等待另一个线程运行到此处，并且交换数据。
 * 
 * </pre>
 * 
 * @author kezhenxu
 *
 */
public class StudyExchanger {

	public static void main(String[] args) {
		// 两个线程交替打印 A B 的面试题
		final Exchanger<Boolean> abTurn = new Exchanger<>();
		final Exchanger<Boolean> bcTurn = new Exchanger<>();
		final Exchanger<Boolean> caTurn = new Exchanger<>();
		new Thread(new PrintTask(true, caTurn, abTurn), "A").start();
		new Thread(new PrintTask(null, abTurn, bcTurn), "B").start();
		new Thread(new PrintTask(null, bcTurn, caTurn), "C").start();
	}

	static class PrintTask implements Runnable {
		private Boolean myTurn;
		private Exchanger<Boolean> previousEx;
		private Exchanger<Boolean> nextEx;

		public PrintTask(Boolean myTurn, Exchanger<Boolean> previousEx, Exchanger<Boolean> nextEx) {
			this.myTurn = myTurn;
			this.previousEx = previousEx;
			this.nextEx = nextEx;
		}

		@Override
		public void run() {
			try {
				for (int i = 0; i < 20; i++) {
					// 避免自动拆箱导致的 NullPointerException 的 trick
					if (Boolean.TRUE != myTurn) {
						myTurn = previousEx.exchange(myTurn);
					} else {
						System.out.print(Thread.currentThread().getName());
						myTurn = nextEx.exchange(myTurn);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void uselessDemo() {
		final Exchanger<Integer> exchanger = new Exchanger<>();
		new Thread(new Counter(null, exchanger)).start();
		new Thread(new Counter(0, exchanger)).start();
	}

	static class Counter implements Runnable {
		private Integer counter;
		private Exchanger<Integer> exchanger;

		public Counter(Integer initial, Exchanger<Integer> exchanger) {
			this.counter = initial;
			this.exchanger = exchanger;
		}

		@Override
		public void run() {
			try {
				while (true) {
					if (counter != null) {
						for (int i = 0; i < 3; i++) {
							counter++;
							System.out.println(Thread.currentThread() + " counter is " + counter);
							Thread.sleep(500);
						}
						if (counter >= 20)
							break;
					}
					counter = exchanger.exchange(counter);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
